package com.tuzhi.util;



import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.time.DateUtils;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;

import static org.apache.commons.lang3.time.DateFormatUtils.ISO_8601_EXTENDED_DATETIME_FORMAT;


/**
 * 功能描述：时间日期工具
 * zhf
 */
public final class DateTzUtil extends DateUtils {


    public final static String DEFAULT_PATTERN = "yyyy-MM-dd HH:mm:ss";
    public final static String DEFAULT_PATTERN_SHORT = "yyyyMMddHHmmss";
    public final static String DEFAULT_PATTERN_YMDHMSS = "yyyy-MM-dd HH:mm:ss:SSS";
    public final static String DEFAULT_PATTERN_YMDHMSS_SHORT = "yyyyMMddHHmmssSSS";
    public final static String DEFAULT_PATTERN_YMDHM = "yyyy-MM-dd HH:mm";
    public final static String DEFAULT_PATTERN_YMDHM_SHORT = "yyyyMMddHHmm";
    public final static String DEFAULT_PATTERN_YMD = "yyyy-MM-dd";
    public final static String DEFAULT_PATTERN_YMD_SHORT = "yyyyMMdd";

    public final static String DEFAULT_PATTERN_YM = "yyyy-MM";
    public final static String DEFAULT_PATTERN_YM_SHORT = "yyyyMM";
    public final static String DEFAULT_PATTERN_HMS = "HH:mm:ss";
    public final static String DEFAULT_PATTERN_HM = "HH:mm";

    private static String[] patterns = null;

    static {
        patterns = new String[]{
                DEFAULT_PATTERN,
                DEFAULT_PATTERN_YMDHMSS,
                DEFAULT_PATTERN_YMDHM,
                DEFAULT_PATTERN_YMD,
                DEFAULT_PATTERN_HMS,
                DEFAULT_PATTERN_HM,
                "yyyy/MM/dd HH:mm:ss",
                "yyyy/MM/dd HH:mm",
                "yyyy/MM/dd",
                "yyyy-MM-dd'T'HH:mm:ss"//ISO_8601_EXTENDED_DATETIME_FORMAT.getPattern()
        };
    }

    /**
     * 默认定义的格式转Date
     * @param strDate
     * @return
     */
    public static Date parseDate(String strDate) {
        try {
            return parseDate(strDate, patterns);
        } catch (ParseException e) {
            //
        }
        return null;
    }

    /**
     * 指定格式转Date
     * @param strDate
     * @param format
     * @return
     */
    public static Date parseDate(String strDate, final String format) {

        SimpleDateFormat dateFormat = null;
        if (StringUtils.isBlank(strDate) || "null".equalsIgnoreCase(strDate.trim())) {
            return null;
        } else {
            dateFormat = new SimpleDateFormat(format);
            try {
                return dateFormat.parse(strDate);
            } catch (ParseException e) {
                return null;
            }
        }
    }

    /**
     * 默认格式（yyyy-MM-dd HH:mm:ss）转字符串
     * @return
     */
    public static String formatNow() {
        return format(new Date(), DEFAULT_PATTERN);
    }

    /**
     * 默认格式（yyyy-MM-dd HH:mm:ss）转字符串
     * @param date
     * @return
     */
    public static String format(Date date) {
        return format(date, DEFAULT_PATTERN);
    }

    /**
     * 默认格式（yyyy-MM-dd）转字符串
     * @param date
     * @return
     */
    public static String formatYMD(Date date) {
        return format(date, DEFAULT_PATTERN_YMD);
    }

    /**
     * 指定格式转字符串
     * @param date
     * @param format
     * @return
     */
    public static String format(Date date, final String format) {
        SimpleDateFormat dateFormat = null;
        if (null == date) {
            return "";
        } else {
            dateFormat = new SimpleDateFormat(format);
            try {
                return dateFormat.format(date);
            } catch (NumberFormatException nfe) {
                return "";
            }
        }
    }

    /**
     * 判断时间是否在两个时间之间，包含等于这两个时间(不区分先后)
     * @param date
     * @param dates
     * @return
     */
    public static boolean isRange(Date date, Date[] dates) {
        if (date == null || dates == null || dates.length != 2) {
            return false;
        }
        long startL = dates[0].getTime();
        long endL = dates[1].getTime();
        if (startL > endL) {
            startL = dates[1].getTime();
            endL = dates[0].getTime();
        }
        return (date.getTime() >= startL && date.getTime() <= endL);
    }

    /**
     * 判断时间是否在两个时间之间，包含等于这两个时间(不区分先后)
     * @param date
     * @param dates
     * @return
     */
    public static boolean isRange(Date date, List<Date> dates) {
        return isRange(date, (Date[]) dates.toArray());
    }

    /**
     * 判断时间是否在两个时间之间，包含等于这两个时间(不区分先后)
     * @param date
     * @param dates
     * @return
     */
    public static boolean isRange(Date date, Set<Date> dates) {
        return isRange(date, (Date[]) dates.toArray());
    }

    public static int getYear(Date date) {
        return transCalendar(date).get(Calendar.YEAR);
    }

    /**
     * 返回对应月份，从1开始，非0开始的月份
     * @param date
     * @return
     */
    public static int getMonthNum(Date date) {
        return transCalendar(date).get(Calendar.MONTH) + 1;
    }

    /**
     * 返回月份下标，从0开始的月份
     * @param date
     * @return
     */
    public static int getMonthIndex(Date date) {
        return transCalendar(date).get(Calendar.MONTH);
    }

    /**
     * 返回天（日历的号）
     * @param date
     * @return
     */
    public static int getDay(Date date) {
        return transCalendar(date).get(Calendar.DAY_OF_MONTH);
    }

    /**
     * 返回24小时制的小时
     * @param date
     * @return
     */
    public static int getHour24(Date date) {
        return transCalendar(date).get(Calendar.HOUR_OF_DAY);
    }

    /**
     * 返回分钟
     * @param date
     * @return
     */
    public static int getMinute(Date date) {
        return transCalendar(date).get(Calendar.MINUTE);
    }

    /**
     * 返回秒
     * @param date
     * @return
     */
    public static int getSecond(Date date) {
        return transCalendar(date).get(Calendar.SECOND);
    }

    /**
     * 返回毫秒
     * @param date
     * @return
     */
    public static int getMillisecond(Date date) {
        return transCalendar(date).get(Calendar.MILLISECOND);
    }

    /**
     * 返回星期的下标，1为星期日，2为星期一，以此类推
     * @param date
     * @return
     */
    public static int getWeek(Date date) {
        return transCalendar(date).get(Calendar.DAY_OF_WEEK);
    }

    /**
     * 返回中文的，日，一，二，三，四，五，六
     * @param date
     * @return
     */
    public static String getWeekCn(Date date) {
        int week = transCalendar(date).get(Calendar.DAY_OF_WEEK);
        if (week == 1) {
            return "日";
        } else if (week == 2) {
            return "一";
        } else if (week == 3) {
            return "二";
        } else if (week == 4) {
            return "三";
        } else if (week == 5) {
            return "四";
        } else if (week == 6) {
            return "五";
        } else {
            return "六";
        }
    }

    public static Calendar transCalendar(Date date) {
        Calendar calendar = GregorianCalendar.getInstance();
        calendar.setTime(date);
        return calendar;
    }

    /**
     * 根据日期获取季度
     *
     * @param dates
     * @return
     */
    public static String getQuarter(Date dates) {
        String quarter = "";
        if (dates != null) {
            int month = getMonthNum(dates);
            switch (month) {
                case 1:
                case 2:
                case 3:
                    quarter = "第一季度";
                    break;
                case 4:
                case 5:
                case 6:
                    quarter = "第二季度";
                    break;
                case 7:
                case 8:
                case 9:
                    quarter = "第三季度";
                    break;
                case 10:
                case 11:
                case 12:
                    quarter = "第四季度";
                    break;
            }
        }
        return quarter;
    }

    /**
     * 计算两时间相差多少毫秒
     * @param date1
     * @param date2
     * @return
     */
    public static int computeMillisecond(Date date1, Date date2) {
        long l1 = date1.getTime();
        long l2 = date2.getTime();
        int rs = (int) Math.abs (l1 - l2);
        return rs;
    }

    /**
     * 计算两时间相差多少天
     * @param date1
     * @param date2
     * @return
     */
    public static int computeDays(Date date1, Date date2) {
        int ms = computeMillisecond(date1, date2);
        int days = ms / (1000 * 60 * 60 * 24);
        return days;
    }

    /**
     * 计算两时间相差多少小时
     * @param date1
     * @param date2
     * @return
     */
    public static int computeHours(Date date1, Date date2) {
        int ms = computeMillisecond(date1, date2);
        int days = ms / (1000 * 60 * 60);
        return days;
    }

    /**
     * 计算两时间相差多少分钟
     * @param date1
     * @param date2
     * @return
     */
    public static int computeMinutes(Date date1, Date date2) {
        int ms = computeMillisecond(date1, date2);
        int rs = ms / (1000 * 60);
        return rs;
    }

    /**
     * 计算两时间相差多少秒
     * @param date1
     * @param date2
     * @return
     */
    public static int computeSecond(Date date1, Date date2) {
        int ms = computeMillisecond(date1, date2);
        int rs = ms / (1000);
        return rs;
    }

    /**
     * 判断是否为同一个日期，truncate为截断指定位置的比较
     * truncate=Calendar.MONTH, （2022-08-02 11:30:29）截取到月，也就是传入时间当月1号（2022-08-01 00:00:00）
     * @param date1
     * @param date2
     * @param truncate
     * @return
     */
    public static boolean isSameDate4Truncate(Date date1, Date date2, int truncate) {
        if (date1 == null && date2 == null) {
            return true;
        } else if (date1 == null && date2 != null) {
            return false;
        }  else if (date1 != null && date2 == null) {
            return false;
        } else {
            Date d1 = truncate(date1, truncate);
            Date d2 = truncate(date2, truncate);
            return d1.getTime() == d2.getTime();
        }
    }

    /**
     * 判断两天是否在同一个周，按周一到周日范围
     * @param date1
     * @param date2
     * @return
     */
    public static boolean isSameWeek4Truncate(Date date1, Date date2) {
        if (date1 == null || date2 == null) {
            return false;
        }
        Date d1 = transMondayStart(date1);
        Date d2 = transMondayStart(date2);
        return isSameDay(d1, d2);
    }

    /**
     * 把传入时间转换为0小时0分钟0秒
     * @param date
     * @return
     */
    public static Date transStart4Day(Date date) {
        if (date != null) {
            return truncate(date, Calendar.DAY_OF_MONTH);
        }
        return null;
    }

    /**
     * 把传入时间转换为23小时59分钟59秒
     * @param date
     * @return
     */
    public static Date transEnd4Day(Date date) {
        if (date != null) {
            Date d = truncate(date, Calendar.DAY_OF_MONTH);
            d = addDays(d, 1);
            d = addMilliseconds(d, -1);
            return d;
        }
        return null;
    }

    /**
     * 设置星期，1-7对应日-六
     * @param date
     * @param index
     * @return
     */
    public static Date setWeek(Date date, int index) {
        if (date != null) {
            Calendar calendar = transCalendar(date);
            calendar.set(Calendar.DAY_OF_WEEK, index);
            return truncate(calendar.getTime(), Calendar.DAY_OF_MONTH);
        }
        return null;
    }

    /**
     * 转换为本周星期一的00:00:00
     * 注：周的范围是周一到周日，起启为周一
     * @param date
     * @return
     */
    public static Date transMondayStart(Date date) {
        if (date != null) {
            Calendar calendar = transCalendar(date);
            int i = calendar.get(Calendar.DAY_OF_WEEK);

            Date d = setWeek(date, 2);
            d = truncate(d, Calendar.DAY_OF_MONTH);

            //如果是星期日，需要算到上周
            if (i == 1) {
                d = addDays(d, -7);
            }

            return d;
        }
        return null;
    }

    /**
     * 转换为本周星期日的23:59:59
     * 注：周的范围是周一到周日，起启为周一
     * @param date
     * @return
     */
    public static Date transSundayEnd(Date date) {
        if (date != null) {
            Calendar calendar = transCalendar(date);
            int i = calendar.get(Calendar.DAY_OF_WEEK);

            Date d = setWeek(date, 1);
            if (i != 1) {
                //不是星期日，需要加7
                d = addDays(d, 7);
            }
            return transEnd4Day(d);
        }
        return null;
    }

    /**
     * 转换为传入时间月份的1号00:00:00
     * @param date
     * @return
     */
    public static Date transStart4Month(Date date) {
        if (date != null) {
            return truncate(date, Calendar.MONTH);
        }
        return null;
    }

    /**
     * 转换为传入时间月份的最后1天23:59:59
     * @param date
     * @return
     */
    public static Date transEnd4Month(Date date) {
        if (date != null) {
            Date d = addMonths(date, 1);
            d = truncate(d, Calendar.MONTH);
            d = addMilliseconds(d, -1);
            return d;
        }
        return null;
    }

    /**
     * 返回时间更大的一个，如果有空，返回空
     * @param date1
     * @param date2
     * @return
     */
    public static Date maxDate(Date date1, Date date2) {
        if (date1 == null || date2 == null) {
           return null;
        }
        if (date1.getTime() > date2.getTime()) {
            return date1;
        }
        return date2;
    }

    /**
     * 返回时间更小的一个，如果有空，返回空
     * @param date1
     * @param date2
     * @return
     */
    public static Date minDate(Date date1, Date date2) {
        if (date1 == null || date2 == null) {
            return null;
        }
        if (date1.getTime() > date2.getTime()) {
            return date2;
        }
        return date1;
    }

    public static List<Date> getRangeDateList(Date date1, Date date2) {
        List<Date> list = new ArrayList<Date>();
        if (date1 == null || date2 == null) {
            return list;
        }

        Date max = truncate(maxDate(date1, date2), Calendar.DAY_OF_MONTH);
        Date min = truncate(minDate(date1, date2), Calendar.DAY_OF_MONTH);
        int cut = computeDays(min, max);

        //超出1000天，只返回1000
        if (cut > 1000) {
            cut = 1000;
        }

        for (int i = 0; i < cut; i++) {
            list.add(addDays(min, i));
        }

        if (!list.isEmpty()) {
            if (!isSameDate4Truncate(list.get(list.size()-1), max, Calendar.DAY_OF_MONTH)) {
                //最后一天不是刚好的max，把max补上
                list.add(max);
            }
        }

        return list;
    }

    /**
     * 判断是否闰年
     * @param date
     * @return
     */
    public static boolean isLeapYear(Date date) {
        /**
         * 详细设计：
         * 1.被400整除是闰年
         * 2.不能被4整除则不是闰年
         * 3.能被4整除同时不能被100整除则是闰年
         * 4.能被4整除同时能被100整除则不是闰年
         */
        int year = getYear(date);
        if ((year % 400) == 0){
            return true;
        }else if ((year % 4) == 0){
            if ((year % 100) == 0){
                return false;
            }else{
                return true;
            }
        }else{
            return false;
        }
    }

    public static void main(String[] args) {
        System.out.println(transStart4Day(new Date()));
        System.out.println(transEnd4Day(new Date()));

        System.out.println(getQuarter(new Date()));
        System.out.println(getMonthNum(new Date()));
        System.out.println(getWeekCn(new Date()));
        System.out.println(getWeek(new Date()));
        System.out.println(getDay(new Date()));
        System.out.println(getHour24(new Date()));
        System.out.println(getMinute(new Date()));
        System.out.println(getSecond(new Date()));

        System.out.println(transMondayStart(parseDate("2022-09-04 12:30:10")));
        System.out.println(transMondayStart(parseDate("2022-09-05 12:30:10")));
        System.out.println(transSundayEnd(parseDate("2022-09-04 12:30:10")));
        System.out.println(transSundayEnd(parseDate("2022-09-05 12:30:10")));

        System.out.println(transStart4Month(new Date()));
        System.out.println(transEnd4Month(new Date()));

        Date d1 = parseDate("2022-08-18 12:30:10");
        Date d2 = parseDate("2022-09-08 11:30:10");
        List<Date> list = getRangeDateList(d1, d2);
        for (Date d: list) {
            System.out.println(format(d));
        }


        Date d3 = parseDate("2022-09-11 12:30:10");
        System.out.println(isSameWeek4Truncate(d2, d3));


    }

}